home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / xulrunner-1.9.0.14 / python / xpcom / client / __init__.py
Encoding:
Python Source  |  2006-11-20  |  22.6 KB  |  533 lines

  1. # ***** BEGIN LICENSE BLOCK *****
  2. # Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. #
  4. # The contents of this file are subject to the Mozilla Public License Version
  5. # 1.1 (the "License"); you may not use this file except in compliance with
  6. # the License. You may obtain a copy of the License at
  7. # http://www.mozilla.org/MPL/
  8. #
  9. # Software distributed under the License is distributed on an "AS IS" basis,
  10. # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. # for the specific language governing rights and limitations under the
  12. # License.
  13. #
  14. # The Original Code is the Python XPCOM language bindings.
  15. #
  16. # The Initial Developer of the Original Code is
  17. # ActiveState Tool Corp.
  18. # Portions created by the Initial Developer are Copyright (C) 2000, 2001
  19. # the Initial Developer. All Rights Reserved.
  20. #
  21. # Contributor(s):
  22. #   Mark Hammond <MarkH@ActiveState.com> (original author)
  23. #
  24. # Alternatively, the contents of this file may be used under the terms of
  25. # either the GNU General Public License Version 2 or later (the "GPL"), or
  26. # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27. # in which case the provisions of the GPL or the LGPL are applicable instead
  28. # of those above. If you wish to allow use of your version of this file only
  29. # under the terms of either the GPL or the LGPL, and not to allow others to
  30. # use your version of this file under the terms of the MPL, indicate your
  31. # decision by deleting the provisions above and replace them with the notice
  32. # and other provisions required by the GPL or the LGPL. If you do not delete
  33. # the provisions above, a recipient may use your version of this file under
  34. # the terms of any one of the MPL, the GPL or the LGPL.
  35. #
  36. # ***** END LICENSE BLOCK *****
  37.  
  38. import os
  39. import new
  40. import logging
  41. from xpcom import xpt, COMException, nsError, logger
  42.  
  43. # Suck in stuff from _xpcom we use regularly to prevent a module lookup
  44. from xpcom._xpcom import IID_nsISupports, IID_nsIClassInfo, \
  45.     IID_nsISupportsCString, IID_nsISupportsString, \
  46.     IID_nsISupportsWeakReference, IID_nsIWeakReference, \
  47.     XPTI_GetInterfaceInfoManager, GetComponentManager, NS_InvokeByIndex
  48.  
  49. # Attribute names we may be __getattr__'d for, but know we don't want to delegate
  50. # Could maybe just look for startswith("__") but this may screw things for some objects.
  51. _special_getattr_names = ["__del__", "__len__", "__nonzero__", "__eq__", "__neq__"]
  52.  
  53. _just_int_interfaces = ["nsISupportsPRInt32", "nsISupportsPRInt16", "nsISupportsPRUint32", "nsISupportsPRUint16", "nsISupportsPRUint8", "nsISupportsPRBool"]
  54. _just_long_interfaces = ["nsISupportsPRInt64", "nsISupportsPRUint64"]
  55. _just_float_interfaces = ["nsISupportsDouble", "nsISupportsFloat"]
  56. # When doing a specific conversion, the order we try the interfaces in.
  57. _int_interfaces = _just_int_interfaces + _just_float_interfaces
  58. _long_interfaces = _just_long_interfaces + _just_int_interfaces + _just_float_interfaces
  59. _float_interfaces = _just_float_interfaces + _just_long_interfaces + _just_int_interfaces
  60.  
  61. method_template = """
  62. def %s(self, %s):
  63.     return NS_InvokeByIndex(self._comobj_, %d, (%s, (%s)))
  64. """
  65. def _MakeMethodCode(method):
  66.     # Build a declaration
  67.     param_no = 0
  68.     param_decls = []
  69.     param_flags = []
  70.     param_names = []
  71.     used_default = 0
  72.     for param in method.params:
  73.         param_no = param_no + 1
  74.         param_name = "Param%d" % (param_no,)
  75.         param_default = ""
  76.         if not param.hidden_indicator and param.IsIn() and not param.IsDipper():
  77.             if param.IsOut() or used_default: # If the param is "inout", provide a useful default for the "in" direction.
  78.                 param_default = " = None"
  79.                 used_default = 1 # Once we have used one once, we must for the rest!
  80.             param_decls.append(param_name + param_default)
  81.             param_names.append(param_name)
  82.  
  83.         type_repr = xpt.MakeReprForInvoke(param)
  84.         param_flags.append( (param.param_flags,) +  type_repr )
  85.     sep = ", "
  86.     param_decls = sep.join(param_decls)
  87.     if len(param_names)==1: # Damn tuple reprs.
  88.         param_names = param_names[0] + ","
  89.     else:
  90.         param_names = sep.join(param_names)
  91.     # A couple of extra newlines make them easier to read for debugging :-)
  92.     return method_template % (method.name, param_decls, method.method_index, tuple(param_flags), param_names)
  93.  
  94. # Keyed by IID, each item is a tuple of (methods, getters, setters)
  95. interface_cache = {}
  96. # Keyed by [iid][name], each item is an unbound method.
  97. interface_method_cache = {}
  98.  
  99. # Keyed by clsid from nsIClassInfo - everything ever queried for the CID.
  100. contractid_info_cache = {}
  101. have_shutdown = 0
  102.  
  103. def _shutdown():
  104.     interface_cache.clear()
  105.     interface_method_cache.clear()
  106.     contractid_info_cache.clear()
  107.     global have_shutdown
  108.     have_shutdown = 1
  109.  
  110. # Fully process the named method, generating method code etc.
  111. def BuildMethod(method_info, iid):
  112.     name = method_info.name
  113.     try:
  114.         return interface_method_cache[iid][name]
  115.     except KeyError:
  116.         pass
  117.     # Generate it.
  118.     assert not (method_info.IsSetter() or method_info.IsGetter()), "getters and setters should have been weeded out by now"
  119.     method_code = _MakeMethodCode(method_info)
  120.     # Build the method - We only build a function object here
  121.     # - they are bound to each instance as needed.
  122.     
  123. ##    print "Method Code for %s (%s):" % (name, iid)
  124. ##    print method_code
  125.     codeObject = compile(method_code, "<XPCOMObject method '%s'>" % (name,), "exec")
  126.     # Exec the code object
  127.     tempNameSpace = {}
  128.     exec codeObject in globals(), tempNameSpace
  129.     ret = tempNameSpace[name]
  130.     if not interface_method_cache.has_key(iid):
  131.         interface_method_cache[iid] = {}
  132.     interface_method_cache[iid][name] = ret
  133.     return ret
  134.  
  135. from xpcom.xpcom_consts import XPT_MD_GETTER, XPT_MD_SETTER, XPT_MD_NOTXPCOM, XPT_MD_CTOR, XPT_MD_HIDDEN
  136. FLAGS_TO_IGNORE = XPT_MD_NOTXPCOM | XPT_MD_CTOR | XPT_MD_HIDDEN
  137.  
  138. # Pre-process the interface - generate a list of methods, constants etc,
  139. # but don't actually generate the method code.
  140. def BuildInterfaceInfo(iid):
  141.     assert not have_shutdown, "Can't build interface info after a shutdown"
  142.     ret = interface_cache.get(iid, None)
  143.     if ret is None:
  144.         # Build the data for the cache.
  145.         method_code_blocks = []
  146.         getters = {}
  147.         setters = {}
  148.         method_infos = {}
  149.         
  150.         interface = xpt.Interface(iid)
  151.         for m in interface.methods:
  152.             flags = m.flags
  153.             if flags & FLAGS_TO_IGNORE == 0:
  154.                 if flags & XPT_MD_SETTER:
  155.                     param_flags = map(lambda x: (x.param_flags,) + xpt.MakeReprForInvoke(x), m.params)
  156.                     setters[m.name] = m.method_index, param_flags
  157.                 elif flags & XPT_MD_GETTER:
  158.                     param_flags = map(lambda x: (x.param_flags,) + xpt.MakeReprForInvoke(x), m.params)
  159.                     getters[m.name] = m.method_index, param_flags
  160.                 else:
  161.                     method_infos[m.name] = m
  162.  
  163.         # Build the constants.
  164.         constants = {}
  165.         for c in interface.constants:
  166.             constants[c.name] = c.value
  167.         ret = method_infos, getters, setters, constants
  168.         interface_cache[iid] = ret
  169.     return ret
  170.  
  171. class _XPCOMBase:
  172.     def __cmp__(self, other):
  173.         try:
  174.             other = other._comobj_
  175.         except AttributeError:
  176.             pass
  177.         return cmp(self._comobj_, other)
  178.  
  179.     def __hash__(self):
  180.         return hash(self._comobj_)
  181.  
  182.     # The basic rich compare ops for equality
  183.     def __eq__(self, other):
  184.         try:
  185.             other = other._comobj_
  186.         except AttributeError:
  187.             pass
  188.         return self._comobj_ == other
  189.  
  190.     def __neq__(self, other):
  191.         try:
  192.             other = other._comobj_
  193.         except AttributeError:
  194.             pass
  195.         return self._comobj_ != other
  196.  
  197.     # See if the object support strings.
  198.     def __str__(self):
  199.         try:
  200.             self._comobj_.QueryInterface(IID_nsISupportsCString, 0)
  201.             return str(self._comobj_)
  202.         except COMException:
  203.             return self.__repr__()
  204.  
  205.     def __unicode__(self):
  206.         try:
  207.             prin = self._comobj_.QueryInterface(IID_nsISupportsString)
  208.         except COMException:
  209.             return unicode(str(self))
  210.         return prin.data
  211.  
  212.     # Try the numeric support.
  213.     def _do_conversion(self, interface_names, cvt):
  214.         iim = XPTI_GetInterfaceInfoManager()
  215.         for interface_name in interface_names:
  216.             iid = iim.GetInfoForName(interface_name).GetIID()
  217.             try:
  218.                 prim = self._comobj_.QueryInterface(iid)
  219.                 return cvt(prim.data)
  220.             except COMException:
  221.                 pass
  222.         raise ValueError, "This object does not support automatic numeric conversion to this type"
  223.  
  224.     def __int__(self):
  225.         return self._do_conversion(_int_interfaces, int)
  226.  
  227.     def __long__(self):
  228.         return self._do_conversion(_long_interfaces, long)
  229.  
  230.     def __float__(self):
  231.         return self._do_conversion(_float_interfaces, float)
  232.     
  233. class Component(_XPCOMBase):
  234.     def __init__(self, ob, iid = IID_nsISupports):
  235.         assert not hasattr(ob, "_comobj_"), "Should be a raw nsIWhatever, not a wrapped one"
  236.         ob_name = None
  237.         if not hasattr(ob, "IID"):
  238.             ob_name = ob
  239.             cm = GetComponentManager()
  240.             ob = cm.createInstanceByContractID(ob)
  241.             assert not hasattr(ob, "_comobj_"), "The created object should be a raw nsIWhatever, not a wrapped one"
  242.         # Keep a reference to the object in the component too
  243.         self.__dict__['_comobj_'] = ob
  244.         # hit __dict__ directly to avoid __setattr__()
  245.         self.__dict__['_interfaces_'] = {} # keyed by IID
  246.         self.__dict__['_interface_names_'] = {} # keyed by IID name
  247.         self.__dict__['_interface_infos_'] = {} # keyed by IID
  248.         self.__dict__['_name_to_interface_iid_'] = {}
  249.         self.__dict__['_tried_classinfo_'] = 0
  250.  
  251.         if ob_name is None:
  252.             ob_name = "<unknown>"
  253.         self.__dict__['_object_name_'] = ob_name
  254.         self.QueryInterface(iid)
  255.  
  256.     def _build_all_supported_interfaces_(self):
  257.         # Use nsIClassInfo, but don't do it at object construction to keep perf up.
  258.         # Only pay the penalty when we really need it.
  259.         assert not self._tried_classinfo_, "already tried to get the class info."
  260.         self.__dict__['_tried_classinfo_'] = 1
  261.         # See if nsIClassInfo is supported.
  262.         try:
  263.             classinfo = self._comobj_.QueryInterface(IID_nsIClassInfo, 0)
  264.         except COMException:
  265.             classinfo = None
  266.         if classinfo is not None:
  267.             try:
  268.                 real_cid = classinfo.contractID
  269.             except COMException:
  270.                 real_cid = None
  271.             if real_cid:
  272.                 self.__dict__['_object_name_'] = real_cid
  273.                 contractid_info = contractid_info_cache.get(real_cid)
  274.             else:
  275.                 contractid_info = None
  276.             if contractid_info is None:
  277.                 try:
  278.                     interface_infos = classinfo.getInterfaces()
  279.                 except COMException:
  280.                     interface_infos = []
  281.                 for nominated_iid in interface_infos:
  282.                     # Interface may appear twice in the class info list, so check this here.
  283.                     if not self.__dict__['_interface_infos_'].has_key(nominated_iid):
  284.                         # Just invoke our QI on the object
  285.                         self.queryInterface(nominated_iid)
  286.                 if real_cid is not None:
  287.                     contractid_info = {}
  288.                     contractid_info['_name_to_interface_iid_'] = self.__dict__['_name_to_interface_iid_']
  289.                     contractid_info['_interface_infos_'] = self.__dict__['_interface_infos_']
  290.                     contractid_info_cache[real_cid] = contractid_info
  291.             else:
  292.                 for key, val in contractid_info.items():
  293.                     self.__dict__[key].update(val)
  294.  
  295.         self.__dict__['_com_classinfo_'] = classinfo
  296.  
  297.     def _remember_interface_info(self, iid):
  298.         # XXX - there is no good reason to cache this only in each instance
  299.         # It should be cached at the module level, so we don't need to
  300.         # rebuild the world for each new object.
  301.         iis = self.__dict__['_interface_infos_']
  302.         assert not iis.has_key(iid), "Already remembered this interface!"
  303.         try:
  304.             method_infos, getters, setters, constants = BuildInterfaceInfo(iid)
  305.         except COMException, why:
  306.             # Failing to build an interface info generally isn't a real
  307.             # problem - its probably just that the interface is non-scriptable.
  308.             logger.info("Failed to build interface info for %s: %s", iid, why)
  309.             # Remember the fact we failed.
  310.             iis[iid] = None
  311.             return
  312.  
  313.         # Remember all the names so we can delegate
  314.         iis[iid] = method_infos, getters, setters, constants
  315.         names = self.__dict__['_name_to_interface_iid_']
  316.         for name in method_infos.keys(): names[name] = iid
  317.         for name in getters.keys(): names[name] = iid
  318.         for name in setters.keys(): names[name] = iid
  319.         for name in constants.keys():  names[name] = iid
  320.  
  321.     def QueryInterface(self, iid):
  322.         if self._interfaces_.has_key(iid):
  323.             assert self._interface_names_.has_key(iid.name), "_interfaces_ has the key, but _interface_names_ does not!"
  324.             return self
  325.         # Haven't seen this before - do a real QI.
  326.         if not self._interface_infos_.has_key(iid):
  327.             self._remember_interface_info(iid)
  328.         iface_info = self._interface_infos_[iid]
  329.         if iface_info is None:
  330.             # We have tried, but failed, to get this interface info.  Its
  331.             # unlikely to work later either - its probably non-scriptable.
  332.             # That means our component wrappers are useless - so just return a
  333.             # raw nsISupports object with no wrapper.            
  334.             return self._comobj_.QueryInterface(iid, 0)
  335.  
  336.         raw_iface = self._comobj_.QueryInterface(iid, 0)
  337.  
  338.         method_infos, getters, setters, constants = iface_info
  339.         new_interface = _Interface(raw_iface, iid, method_infos,
  340.                                    getters, setters, constants)
  341.         self._interfaces_[iid] = new_interface
  342.         self._interface_names_[iid.name] = new_interface
  343.         # As we 'flatten' objects when possible, a QI on an object just
  344.         # returns ourself - all the methods etc on this interface are
  345.         # available.
  346.         return self
  347.  
  348.     queryInterface = QueryInterface # Alternate name.
  349.  
  350.     def __getattr__(self, attr):
  351.         if attr in _special_getattr_names:
  352.             raise AttributeError, attr
  353.         # First allow the interface name to return the "raw" interface
  354.         interface = self.__dict__['_interface_names_'].get(attr, None)
  355.         if interface is not None:
  356.             return interface
  357.         # See if we know the IID of an interface providing this attribute
  358.         iid = self.__dict__['_name_to_interface_iid_'].get(attr, None)
  359.         # This may be first time trying this interface - get the nsIClassInfo
  360.         if iid is None and not self._tried_classinfo_:
  361.             self._build_all_supported_interfaces_()
  362.             iid = self.__dict__['_name_to_interface_iid_'].get(attr, None)
  363.             # If the request is for an interface name, it may now be
  364.             # available.
  365.             interface = self.__dict__['_interface_names_'].get(attr, None)
  366.             if interface is not None:
  367.                 return interface
  368.  
  369.         if iid is not None:
  370.             interface = self.__dict__['_interfaces_'].get(iid, None)
  371.             if interface is None:
  372.                 self.QueryInterface(iid)
  373.                 interface = self.__dict__['_interfaces_'][iid]
  374.             return getattr(interface, attr)
  375.         # Some interfaces may provide this name via "native" support.
  376.         # Loop over all interfaces, and if found, cache it for next time.
  377.         for interface in self.__dict__['_interfaces_'].values():
  378.             try:
  379.                 ret = getattr(interface, attr)
  380.                 self.__dict__['_name_to_interface_iid_'][attr] = interface._iid_
  381.                 return ret
  382.             except AttributeError:
  383.                 pass
  384.         raise AttributeError, "XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr)
  385.         
  386.     def __setattr__(self, attr, val):
  387.         iid = self._name_to_interface_iid_.get(attr, None)
  388.         # This may be first time trying this interface - get the nsIClassInfo
  389.         if iid is None and not self._tried_classinfo_:
  390.             self._build_all_supported_interfaces_()
  391.             iid = self.__dict__['_name_to_interface_iid_'].get(attr, None)
  392.         if iid is not None:
  393.             interface = self._interfaces_.get(iid, None)
  394.             if interface is None:
  395.                 self.QueryInterface(iid)
  396.                 interface = self.__dict__['_interfaces_'][iid]
  397.             setattr(interface, attr, val)
  398.             return
  399.         raise AttributeError, "XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr)
  400.  
  401.     def _get_classinfo_repr_(self):
  402.         try:
  403.             if not self._tried_classinfo_:
  404.                 self._build_all_supported_interfaces_()
  405.             assert self._tried_classinfo_, "Should have tried the class info by now!"
  406.         except COMException:
  407.             # Error building the info - ignore the error, but ensure that
  408.             # we are flagged as *not* having built, so the error is seen
  409.             # by the first caller who actually *needs* this to work.
  410.             self.__dict__['_tried_classinfo_'] = 0
  411.  
  412.         iface_names = self.__dict__['_interface_names_'].keys()
  413.         try:
  414.             iface_names.remove("nsISupports")
  415.         except ValueError:
  416.             pass
  417.         iface_names.sort()
  418.         
  419.         iface_desc = "implementing %s" % (",".join(iface_names),)
  420.         return iface_desc
  421.         
  422.     def __repr__(self):
  423.         # We can advantage from nsIClassInfo - use it.
  424.         iface_desc = self._get_classinfo_repr_()
  425.         return "<XPCOM component '%s' (%s)>" % (self._object_name_,iface_desc)
  426.  
  427. class _Interface(_XPCOMBase):
  428.     def __init__(self, comobj, iid, method_infos, getters, setters, constants):
  429.         self.__dict__['_comobj_'] = comobj
  430.         self.__dict__['_iid_'] = iid
  431.         self.__dict__['_property_getters_'] = getters
  432.         self.__dict__['_property_setters_'] = setters
  433.         self.__dict__['_method_infos_'] = method_infos # method infos waiting to be turned into real methods.
  434.         self.__dict__['_methods_'] = {} # unbound methods
  435.         self.__dict__['_object_name_'] = iid.name
  436.         self.__dict__.update(constants)
  437.         # We remember the constant names to prevent the user trying to assign to them!
  438.         self.__dict__['_constant_names_'] = constants.keys()
  439.  
  440.     def __getattr__(self, attr):
  441.         # Allow the underlying interface to provide a better implementation if desired.
  442.         if attr in _special_getattr_names:
  443.             raise AttributeError, attr
  444.  
  445.         ret = getattr(self.__dict__['_comobj_'], attr, None)
  446.         if ret is not None:
  447.             return ret
  448.         # Do the function thing first.
  449.         unbound_method = self.__dict__['_methods_'].get(attr, None)
  450.         if unbound_method is not None:
  451.             return new.instancemethod(unbound_method, self, self.__class__)
  452.  
  453.         getters = self.__dict__['_property_getters_']
  454.         info = getters.get(attr)
  455.         if info is not None:
  456.             method_index, param_infos = info
  457.             if len(param_infos)!=1: # Only expecting a retval
  458.                 raise RuntimeError, "Can't get properties with this many args!"
  459.             args = ( param_infos, () )
  460.             return NS_InvokeByIndex(self._comobj_, method_index, args)
  461.  
  462.         # See if we have a method info waiting to be turned into a method.
  463.         # Do this last as it is a one-off hit.
  464.         method_info = self.__dict__['_method_infos_'].get(attr, None)
  465.         if method_info is not None:
  466.             unbound_method = BuildMethod(method_info, self._iid_)
  467.             # Cache it locally
  468.             self.__dict__['_methods_'][attr] = unbound_method
  469.             return new.instancemethod(unbound_method, self, self.__class__)
  470.  
  471.         raise AttributeError, "XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr)
  472.  
  473.     def __setattr__(self, attr, val):
  474.         # If we already have a __dict__ item of that name, and its not one of
  475.         # our constants, we just directly set it, and leave.
  476.         if self.__dict__.has_key(attr) and attr not in self.__dict__['_constant_names_']:
  477.             self.__dict__[attr] = val
  478.             return
  479.         # Start sniffing for what sort of attribute this might be?
  480.         setters = self.__dict__['_property_setters_']
  481.         info = setters.get(attr)
  482.         if info is None:
  483.             raise AttributeError, "XPCOM component '%s' can not set attribute '%s'" % (self._object_name_, attr)
  484.         method_index, param_infos = info
  485.         if len(param_infos)!=1: # Only expecting a single input val
  486.             raise RuntimeError, "Can't set properties with this many args!"
  487.         real_param_infos = ( param_infos, (val,) )
  488.         return NS_InvokeByIndex(self._comobj_, method_index, real_param_infos)
  489.  
  490.     def __repr__(self):
  491.         return "<XPCOM interface '%s'>" % (self._object_name_,)
  492.  
  493.  
  494. # Called by the _xpcom C++ framework to wrap interfaces up just
  495. # before they are returned.
  496. def MakeInterfaceResult(ob, iid):
  497.     return Component(ob, iid)
  498.  
  499. class WeakReference:
  500.     """A weak-reference object.  You construct a weak reference by passing
  501.     any COM object you like.  If the object does not support weak
  502.     refs, you will get a standard NS_NOINTERFACE exception.
  503.  
  504.     Once you have a weak-reference, you can "call" the object to get
  505.     back a strong reference.  Eg:
  506.  
  507.     >>> some_ob = components.classes['...']
  508.     >>> weak_ref = WeakReference(some_ob)
  509.     >>> new_ob = weak_ref() # new_ob is effectively "some_ob" at this point
  510.     >>> # EXCEPT: new_ob may be None if some_ob has already died - a
  511.     >>> # weak reference does not keep the object alive (that is the point)
  512.  
  513.     You should never hold onto this resulting strong object for a long time,
  514.     or else you defeat the purpose of the weak-reference.
  515.     """
  516.     def __init__(self, ob, iid = None):
  517.         swr = Component(ob._comobj_, IID_nsISupportsWeakReference)
  518.         self._comobj_ = Component(swr.GetWeakReference()._comobj_, IID_nsIWeakReference)
  519.         if iid is None:
  520.             try:
  521.                 iid = ob.IID
  522.             except AttributeError:
  523.                 iid = IID_nsISupports
  524.         self._iid_ = iid
  525.     def __call__(self, iid = None):
  526.         if iid is None: iid = self._iid_
  527.         try:
  528.             return Component(self._comobj_.QueryReferent(iid)._comobj_, iid)
  529.         except COMException, details:
  530.             if details.errno != nsError.NS_ERROR_NULL_POINTER:
  531.                 raise
  532.             return None
  533.